/**
 * @project: BrickCAD
 * @className: AppFrame.java
 * @package: default
 * @author: Sean , Jack, Lester, Erik Telstad
 * @date_created: November 16, 2009
 * @last_motified: November 16, 2009
 * 
 * @Class_Description:
 *      BrickCAD's main class. In this class a Main application frame is created
 *      in which all other frames (views) will be displayed. The frame has a menu
 *      bar... 
 * 
 */


import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JDesktopPane;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;

//import mazeChallenge.Maze;

import guiUtils.GUIUtils;

public class AppFrame extends JFrame {
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	static String title = "BrickCAD Turbo";
	
	private String[] fileMenuItems = { 	"&New",
										"&Open",
										"&Save",
										"Save &As",
										"&Exit" 
										};
	
	private String[] viewMenuItems = { 	"&Top",
										"&Side",
										"&Front",
										"&Data"
										};
	
	private String[] editMenuItems = { 	"&Undo",
										"&Redo",
										"Edit &Width",
										"Edit &Height",
										"Edit &Length",
										};

	private JDesktopPane desktop; 
	private JMenuBar menuBar;
	private JMenu fileMenu, viewMenu, editMenu;
	private FileMenuController fileControl = new FileMenuController();
	private ViewMenuController viewControl = new ViewMenuController();
	private EditMenuController editControl = new EditMenuController();
    protected Brick model;
    protected CommandProcessor cmmdProc = new CommandProcessor();
    protected ArrayList<BrickView> views = new ArrayList<BrickView>();
    //private int i = 0;
    
    /**
     * 
     */
    public AppFrame(){
    	desktop = new JDesktopPane();
//        JPanel mainPanel = new JPanel();
    	setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setDefaultLookAndFeelDecorated(true);
		
        //Make the big window be indented 50 pixels from each edge
        //of the screen.
        int inset = 100;
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds(inset, inset,
                  screenSize.width/2,
                  screenSize.height/2);

		
		desktop = new JDesktopPane(); //a specialized layered pane
        setContentPane(desktop);
        
        menuBar = new JMenuBar();
        setJMenuBar(menuBar);
        
		fileMenu = GUIUtils.makeMenu("File", fileMenuItems, fileControl);
		editMenu = GUIUtils.makeMenu("Edit", editMenuItems, editControl);
		viewMenu = GUIUtils.makeMenu("View", viewMenuItems, viewControl);
		
		menuBar.add(fileMenu);
		menuBar.add(editMenu);
		menuBar.add(viewMenu);


    }
    
	/**
	 * @author Sean O'Brien
	 * 
	 * FileMenuController - an inner class of the application frame that
	 * handles action events generated by the file menu.
	 *
	 */
	class FileMenuController implements ActionListener {

		private File currentDir;
		
		/**
		 * Asks user if model should be saved
		 * @return true if yes
		 */
		private boolean saveChanges() {
			if (!model.isChanged()) return false;
			int choice = JOptionPane.showConfirmDialog(AppFrame.this, "save changes?");
			return choice == 0;
		}

		/**
		 * Saves model to selected file.
		 * @param saveAs prompt user for new file if true
		 */
		private void save(boolean saveAs) {
//			Maze theMaze = gui.getTheModel();
			if (!saveAs && !model.isChanged()) return; // nothing to do
			File f = model.getFile();
			if (f == null || saveAs) {
				f = getFile();
				model.setFile(f);
			}
			try {
				ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
				oos.writeObject(model);
				model.setChanged(false);
			} catch(Exception e) {
				GUIUtils.error(e.getMessage());
			}
		}

		/**
		 * Prompts user for file to be saved or open
		 * @return the selected file
		 */
		private File getFile() {
			 JFileChooser chooser = new JFileChooser();
			 if (currentDir != null) {
				 chooser.setCurrentDirectory(currentDir);
			 }
			 chooser.showOpenDialog(AppFrame.this);
			 File result = chooser.getSelectedFile();
			 currentDir = result.getParentFile();
			 return result;
		}

		/**
		 * Replaces existing model with model read from selected file.
		 */
		private void open() {
			File f = getFile();
			try {
				ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
				Brick savedBrick = (Brick)ois.readObject();
				model = savedBrick;
			} catch(Exception e) {
				GUIUtils.error(e.getMessage());
			}
		}

		private void closeViews() {
			views.trimToSize();
			Iterator<BrickView> iter = views.iterator();
			while(iter.hasNext())
				iter.next().dispose();
			views.clear();
		}


		public void actionPerformed(ActionEvent e) {
			String cmmd = e.getActionCommand();
	        if(cmmd.equals("Exit")) { //exit
	        	System.out.println("Exiting the program...");
				if (saveChanges()) save(false);
				closeViews();
				System.exit(0);
	        	
	        }
			if (cmmd.equals("New")) { //new
	        	System.out.println("Creating a New Brick file...");
	            if(model != null) {
					if (saveChanges()) save(false);
					closeViews();
	            }
	        	model = new Brick();

			}else if (cmmd.equals("Save")) { //save
	        	System.out.println("Saving a Brick file...");
	        	save(false);
        	
	        }else if(cmmd.equals("Save As")) { //save as
	        	System.out.println("Saving a Brick file As...");
				save(true);

	        }else if(cmmd.equals("Open")) { //open
	        	System.out.println("Opening a Brick file...");
	        	if(model != null)
	        		if (saveChanges()) save(false);
				open();
				closeViews();
/*				views.trimToSize();
				Iterator<BrickView> iter = views.iterator();
				while(iter.hasNext())
					iter.next().dispose();
				views.clear();
*/	        	
	        }else  { // unrecognized command
				GUIUtils.error("unrecognized command: " + cmmd);
			}
		}
	}

	/**
	 * @author Sean O'Brien
	 * 
	 * ViewMenuController - an inner class of the application frame that
	 * handles action events generated by the view menu.
	 *
	 */
	class ViewMenuController implements ActionListener {
		public void actionPerformed(ActionEvent e) {
	        String cmmd = e.getActionCommand();
	        createView(cmmd);
		}
	}

    //Create a new internal frame.
    public void createView(String view) {
    	if(view.equals("Data")) 
    		views.add(new DimensionView(model));
    	else if(view.equals("Top"))
    		views.add(new TopView(model));
    	else if(view.equals("Front"))
    		views.add(new FrontView(model));
    	else if(view.equals("Side"))
    		views.add(new SideView(model));
    	int lastIndex = views.size() - 1;
        views.get(lastIndex).setVisible(true); //necessary as of 1.3
        desktop.add(views.get(lastIndex));
        

        try {
        	views.get(lastIndex).setSelected(true);
        } catch (java.beans.PropertyVetoException e) {}
    }


	/**
	 * @author Sean O'Brien
	 * 
	 * EditMenuController - an inner class of the application frame that
	 * handles action events generated by the edit menu.
	 *
	 */
	class EditMenuController implements ActionListener {
		
		private double getValue(String prompt, double initValue) throws IllegalArgumentException {
			String response = JOptionPane.showInputDialog(prompt, (Double)initValue);
			if((response.charAt(0) == '-') || (Double.parseDouble(response) == 0))
				throw new IllegalArgumentException();
			else
				return new Double(response);
		}

		public void actionPerformed(ActionEvent e) {
			String cmmd = e.getActionCommand();
			double value = 0;
			try {
				if(cmmd.equals("Edit Height")) {
					value = getValue("Enter height", model.getHeight());
//					if(value != 0) {
						cmmdProc.execute(new SetHeightCommand(value));
						
//					}
				} else if(cmmd.equals("Edit Width")) {
					value = getValue("Enter width", model.getWidth());
					if(value != 0) {
						cmmdProc.execute(new SetWidthCommand(value));
						
					}
				} else if(cmmd.equals("Edit Length")) {
					value = getValue("Enter length", model.getLength());
					if(value != 0) {
						cmmdProc.execute(new SetLengthCommand(value));
						
					}
				} else if(cmmd.equals("Redo")) {
					System.out.println("Received a Redo command.");
				} else if(cmmd.equals("Undo")) {
					System.out.println("Received an Undo command.");
				}
			} catch(NumberFormatException nfe) {
				JOptionPane.showMessageDialog(AppFrame.this, "Input must be numerical");
			} catch(IllegalArgumentException iae) {
				JOptionPane.showMessageDialog(AppFrame.this, "Input must be greater than 0");
			}
						
		}
	}

	public static void main(String[] args) {
        AppFrame frame = new AppFrame();
        //frame.setSize(500, 500);
//        frame.setLocation(x, y)
        frame.setTitle(title);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
       }

}
